using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    /// <summary>
    /// 掉落物飞向玩家化身的表现基类
    /// </summary>
    public abstract class DropItemPlay : IReusableClass
    {
        private AutoResetUniTaskCompletionSource _throwAnimTask;
        private AutoResetUniTaskCompletionSource _followAnimTask;

        protected Vector3 _startPosition;
        protected Vector3? _landingPosition;
        protected readonly float _gravity = 9.8f;
        protected Entity _dropEntity;
        protected float _throwFlightTime;
        protected Vector3 _throwVelocity;
        protected float _throwTimeElapsed;
        protected Transform _followingTrans;
        protected Vector3 _flyingStartPos;
        protected float _followTimeElapsed;

        public bool isExpired { get; private set; }
        public abstract Transform dropHolder { get; }
        public abstract TViewEntity playerAvatarEntity { get; }
        public virtual uint MaxStore => 10;

        public abstract UniTask<Entity> ShowDrop(int itemCid, bool isLightBeam, Vector3 position);
        public abstract void HideDrop(Entity entity);

        public virtual async UniTask Show(int itemCid, int itemNum, Vector3 startPosition, Vector3 landingPosition)
        {
            _startPosition = startPosition;
            //显示掉落物特效
            _dropEntity = await ShowDrop(itemCid, false, landingPosition);
            //抛出掉落物
            await ThrowDropTo(landingPosition);
            //显示光柱
            var beamEntity = await ShowDrop(itemCid, true, landingPosition);
            //等待1秒
            await UniTask.Delay(GameGlobalConst.SceneDropBeamDuration);
            //隐藏光柱
            HideDrop(beamEntity);
            //掉落物特效飞向玩家
            await FollowPlayer();
            //隐藏特效
            HideDrop(_dropEntity);
            //UI展示掉落信息
            NoticeModule.ShowNoticeFloatItem(itemCid, itemNum);
            //标记为失效，外部Update回收
            isExpired = true;
        }

        private UniTask ThrowDropTo(Vector3 landingPosition)
        {
            _landingPosition = landingPosition;
            // 计算总飞行时间
            float horizontalDistance = Vector3.Distance(new Vector3(_startPosition.x, 0, _startPosition.z), new Vector3(landingPosition.x, 0, landingPosition.z));
            _throwFlightTime = horizontalDistance / GameGlobalConst.SceneDropThrowSpeed;
            // 计算初始速度的方向
            Vector3 direction = (landingPosition - _startPosition).normalized;
            // 计算水平方向速度
            _throwVelocity = direction * GameGlobalConst.SceneDropThrowSpeed;
            // 计算垂直方向速度（抛物线顶点时刻初速度为零，下降阶段反向加速）
            _throwVelocity.y = (landingPosition.y - _startPosition.y + 0.5f * _gravity * _throwFlightTime * _throwFlightTime) / _throwFlightTime;
            _throwAnimTask = AutoResetUniTaskCompletionSource.Create();
            return _throwAnimTask.Task;
        }

        private UniTask FollowPlayer()
        {
            var bindCom = playerAvatarEntity.GetComponent<EntityBindPointComponent>(ETComponentType.EntityBindPoint);
            if (bindCom == null)
            {
                _followingTrans = playerAvatarEntity.transform;
            }
            else
            {
                _followingTrans = bindCom.GetBindPoint(EntityBindPointCommonType.Middle);
            }
            _flyingStartPos = _dropEntity.transform.position;
            _followAnimTask = AutoResetUniTaskCompletionSource.Create();
            return _followAnimTask.Task;
        }

        /// <summary>
        /// 动画帧刷，由外部系统调用，同时也要由调用处判断isExpired并调用Release()
        /// </summary>
        /// <param name="deltaTime"></param>
        public void Update(float deltaTime)
        {
            //抛物线
            if (_landingPosition != null)
            {
                _throwTimeElapsed += deltaTime;
                if (_throwTimeElapsed <= _throwFlightTime)
                {
                    // 计算新位置
                    Vector3 newPosition = _startPosition + _throwVelocity * _throwTimeElapsed;
                    newPosition.y = _startPosition.y + _throwVelocity.y * _throwTimeElapsed - 0.5f * _gravity * _throwTimeElapsed * _throwTimeElapsed;
                    _dropEntity.transform.position = newPosition;
                }
                else
                {
                    _landingPosition = null;
                    // 注意！这里要先置空，再调用，TrySetResult会先调用await之后的代码，如果await之后有给TaskSource赋新值，然后这里再置空，那么_completeActTaskSource就永远为null了。
                    // 若置空不及时导致了多次source.TrySetResult，会导致池内数据异常
                    var taskSrc = _throwAnimTask;
                    _throwAnimTask = null;
                    taskSrc.TrySetResult();
                }
            }
            //飞向玩家化身
            if (_followingTrans != null)
            {
                _followTimeElapsed += deltaTime;
                var learpValue = _followTimeElapsed / GameGlobalConst.SceneDropFlyToHeroSpeed;
                var flyingTrans = _dropEntity.transform;
                // 更新飞行物体的位置
                flyingTrans.position = Vector3.Lerp(_flyingStartPos, _followingTrans.position, learpValue);
                // 当飞行物体非常接近目标时，停止飞行
                if ((flyingTrans.position - _followingTrans.position).sqrMagnitude < 0.01f)
                {
                    flyingTrans.position = _followingTrans.position; // 精确对齐
                    _followingTrans = null;

                    var taskSrc = _followAnimTask;
                    _followAnimTask = null;
                    taskSrc.TrySetResult();
                }
            }
        }

        public void OnReset()
        {
            if (_throwAnimTask != null)
            {
                _throwAnimTask.TrySetCanceled();
                _throwAnimTask = null;
            }
            if (_followAnimTask != null)
            {
                _followAnimTask.TrySetCanceled();
                _followAnimTask = null;
            }
            _startPosition = default;
            _landingPosition = null;
            _dropEntity = null;
            _throwFlightTime = 0;
            _throwVelocity = default;
            _throwTimeElapsed = 0;
            isExpired = false;
            _followingTrans = null;
            _flyingStartPos = default;
            _followTimeElapsed = 0;
        }

        public virtual void Release()
        {
            ClassPool.PutAutoType(this);
        }
    }
}
